#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <cmath>
#include <limits>
#include <optional>
#include <string>

using namespace serializer;

/**
 * 使用统一的 CPO 接口完成一次往返序列化
 * 参数:
 * - value 输入值
 * - options 序列化选项
 * 返回值: 反序列化得到的同类型值
 * 异常: 若序列化/反序列化过程出现错误，将抛出 std::runtime_error 等
 */
template <typename T>
T
roundtrip_via_cpo(const T & value, const default_options & options)
{
    vector_writer writer;
    serialize(writer, value, options);
    vector_reader reader(writer.data());
    return deserialize_cpo(reader, options, type_tag<T>);
}

TEST(cpo_basic_types_test, arithmetic_types_roundtrip)
{
    default_options options{};

    int int_value = 123456789;
    double double_value = 3.1415926;
    bool bool_value = true;

    auto int_out = roundtrip_via_cpo(int_value, options);
    auto double_out = roundtrip_via_cpo(double_value, options);
    auto bool_out = roundtrip_via_cpo(bool_value, options);

    EXPECT_EQ(int_out, int_value);
    EXPECT_DOUBLE_EQ(double_out, double_value);
    EXPECT_EQ(bool_out, bool_value);
}

TEST(cpo_basic_types_test, string_roundtrip_and_empty)
{
    default_options options{};

    std::string s = "hello cpo";
    auto s_out = roundtrip_via_cpo(s, options);
    EXPECT_EQ(s_out, s);

    std::string empty = "";
    auto empty_out = roundtrip_via_cpo(empty, options);
    EXPECT_EQ(empty_out, empty);
}

TEST(cpo_basic_types_test, byte_order_is_respected)
{
    default_options options{};
    int value = 0x12345678;

    auto le = options.with_byte_order(byte_order::little_endian);
    auto be = options.with_byte_order(byte_order::big_endian);

    // 小端
    {
        vector_writer writer;
        serialize(writer, value, le);
        vector_reader reader(writer.data());
        auto out = deserialize_cpo(reader, le, type_tag<int>);
        EXPECT_EQ(out, value);
    }
    // 大端
    {
        vector_writer writer;
        serialize(writer, value, be);
        vector_reader reader(writer.data());
        auto out = deserialize_cpo(reader, be, type_tag<int>);
        EXPECT_EQ(out, value);
    }
}

TEST(cpo_long_double_test, roundtrip_normal_values_varint_on)
{
    // 开启十进制文本策略与变长长度前缀
    auto options =
        default_options{}.with_prefer_decimal_for_long_double(true).with_varint_lengths(true);

    long double v0 = 0.0L;
    long double v1 = 1.0L;
    long double v_1 = -1.0L;

    auto out0 = roundtrip_via_cpo(v0, options);
    auto out1 = roundtrip_via_cpo(v1, options);
    auto out_1 = roundtrip_via_cpo(v_1, options);

    EXPECT_EQ(out0, v0);
    EXPECT_EQ(out1, v1);
    EXPECT_EQ(out_1, v_1);
}

TEST(cpo_long_double_test, roundtrip_normal_values_varint_off)
{
    // 开启十进制文本策略，关闭变长长度前缀
    auto options =
        default_options{}.with_prefer_decimal_for_long_double(true).with_varint_lengths(false);

    long double v0 = 0.0L;
    long double v1 = 1.0L;
    long double v_1 = -1.0L;

    auto out0 = roundtrip_via_cpo(v0, options);
    auto out1 = roundtrip_via_cpo(v1, options);
    auto out_1 = roundtrip_via_cpo(v_1, options);

    EXPECT_EQ(out0, v0);
    EXPECT_EQ(out1, v1);
    EXPECT_EQ(out_1, v_1);
}

TEST(cpo_long_double_test, roundtrip_extreme_values_varint_on_off)
{
    // 对极值进行往返验证，分别在 varint 开启与关闭时测试
    long double vmax = std::numeric_limits<long double>::max();
    long double vmin = std::numeric_limits<long double>::lowest();
    long double vmin_positive = std::numeric_limits<long double>::min();

    // 为避免潜在的字符串长度限制，设置较大的上限
    auto opt_varint_on = default_options{}
                             .with_prefer_decimal_for_long_double(true)
                             .with_varint_lengths(true)
                             .with_max_string_length(10000);
    auto opt_varint_off = default_options{}
                              .with_prefer_decimal_for_long_double(true)
                              .with_varint_lengths(false)
                              .with_max_string_length(10000);

    auto out_max_on = roundtrip_via_cpo(vmax, opt_varint_on);
    auto out_min_on = roundtrip_via_cpo(vmin, opt_varint_on);
    auto out_min_pos_on = roundtrip_via_cpo(vmin_positive, opt_varint_on);
    auto out_max_off = roundtrip_via_cpo(vmax, opt_varint_off);
    auto out_min_off = roundtrip_via_cpo(vmin, opt_varint_off);
    auto out_min_pos_off = roundtrip_via_cpo(vmin_positive, opt_varint_off);

    EXPECT_EQ(out_max_on, vmax);
    EXPECT_EQ(out_min_on, vmin);
    EXPECT_EQ(out_min_pos_on, vmin_positive);
    EXPECT_EQ(out_max_off, vmax);
    EXPECT_EQ(out_min_off, vmin);
    EXPECT_EQ(out_min_pos_off, vmin_positive);
}

TEST(cpo_long_double_test, roundtrip_non_finite_values_varint_on_off)
{
    // 非有限值：nan、inf、-inf
    long double vnan = std::numeric_limits<long double>::quiet_NaN();
    long double vinf = std::numeric_limits<long double>::infinity();
    long double vneg_inf = -std::numeric_limits<long double>::infinity();

    auto opt_on =
        default_options{}.with_prefer_decimal_for_long_double(true).with_varint_lengths(true);
    auto opt_off =
        default_options{}.with_prefer_decimal_for_long_double(true).with_varint_lengths(false);

    // varint 开启
    {
        auto out_nan = roundtrip_via_cpo(vnan, opt_on);
        auto out_inf = roundtrip_via_cpo(vinf, opt_on);
        auto out_neg_inf = roundtrip_via_cpo(vneg_inf, opt_on);

        EXPECT_TRUE(std::isnan(out_nan));
        EXPECT_TRUE(std::isinf(out_inf));
        EXPECT_FALSE(std::signbit(out_inf));
        EXPECT_TRUE(std::isinf(out_neg_inf));
        EXPECT_TRUE(std::signbit(out_neg_inf));
    }
    // varint 关闭
    {
        auto out_nan = roundtrip_via_cpo(vnan, opt_off);
        auto out_inf = roundtrip_via_cpo(vinf, opt_off);
        auto out_neg_inf = roundtrip_via_cpo(vneg_inf, opt_off);

        EXPECT_TRUE(std::isnan(out_nan));
        EXPECT_TRUE(std::isinf(out_inf));
        EXPECT_FALSE(std::signbit(out_inf));
        EXPECT_TRUE(std::isinf(out_neg_inf));
        EXPECT_TRUE(std::signbit(out_neg_inf));
    }
}

TEST(cpo_long_double_test, max_string_length_exceeded_should_throw_varint_off)
{
    // 关闭变长长度前缀时，上限检查在反序列化阶段也应生效
    auto write_options = default_options{}
                             .with_prefer_decimal_for_long_double(true)
                             .with_varint_lengths(false)
                             .with_max_string_length(10000);
    auto read_options = default_options{}
                            .with_prefer_decimal_for_long_double(true)
                            .with_varint_lengths(false)
                            .with_max_string_length(4);

    long double value = 12345.6L; // 十进制文本长度显著大于 4

    vector_writer writer;
    serialize(writer, value, write_options); // 先用较大上限写入生成负载
    vector_reader reader(writer.data());

    EXPECT_THROW(deserialize<long double>(reader, read_options), std::runtime_error);
}

TEST(cpo_long_double_test, max_string_length_exceeded_should_throw)
{
    // 开启变长长度前缀时，上限检查在反序列化阶段也应生效
    auto write_options = default_options{}
                             .with_prefer_decimal_for_long_double(true)
                             .with_varint_lengths(true)
                             .with_max_string_length(10000);
    auto read_options = default_options{}
                            .with_prefer_decimal_for_long_double(true)
                            .with_varint_lengths(true)
                            .with_max_string_length(3);

    long double value = 1234.5L; // 十进制文本长度显著大于 3

    vector_writer writer;
    serialize(writer, value, write_options); // 先用较大上限写入生成负载
    vector_reader reader(writer.data());

    EXPECT_THROW(deserialize<long double>(reader, read_options), std::runtime_error);
}

TEST(cpo_long_double_test, prefer_decimal_disabled_should_throw)
{
    // 显式关闭十进制文本策略时，序列化 long double 应抛出异常
    auto options = default_options{}.with_prefer_decimal_for_long_double(false);
    long double value = 3.14L;

    vector_writer writer;
    EXPECT_THROW(serialize(writer, value, options), std::runtime_error);
}